package wxopen_api

import (
	"context"
	"fmt"
	"net/http"
)

// ComponentService Wechat API docs: https://developers.weixin.qq.com/doc/
type ComponentService service

// APIComponentTokenRequest represents a request to get a token.
type APIComponentTokenRequest struct {
	ComponentAppID        string `json:"component_appid"`
	ComponentAppSecret    string `json:"component_appsecret"`
	ComponentVerifyTicket string `json:"component_verify_ticket"`
}

// Token represents a API token on a component.
type Token struct {
	ComponentAccessToken string `json:"component_access_token"`
	ExpiresIn            int64  `json:"expires_in"`
}

// APIComponentToken fetch a new api component token.
//
// Wechat API docs:
// https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/component_access_token.html
func (s *ComponentService) APIComponentToken(ctx context.Context, r *APIComponentTokenRequest) (*Token, *Response, error) {
	u := "cgi-bin/component/api_component_token"
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, nil, err
	}
	token := new(Token)
	resp, err := s.client.Do(ctx, req, token)
	if err != nil {
		return nil, resp, err
	}
	return token, resp, nil
}

// FastRegisterWeAppRequest represents a request to create a mini program.
type FastRegisterWeAppRequest struct {
	Name               string `json:"name"`
	Code               string `json:"code"`
	CodeType           int    `json:"code_type"`
	LegalPersonaWechat string `json:"legal_persona_wechat"`
	LegalPersonaName   string `json:"legal_persona_name"`
	ComponentPhone     string `json:"component_phone"`
}

// FastRegisterWeApp create a new mini program.
//
// Wechat API docs:
// https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html
func (s *ComponentService) FastRegisterWeApp(ctx context.Context, token string, r *FastRegisterWeAppRequest) (*Response, error) {
	u := fmt.Sprintf("cgi-bin/component/fastregisterweapp?action=create&component_access_token=%v", token)
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, err
	}
	return s.client.Do(ctx, req, nil)
}

// CreatePreAuthCodeRequest create pre_auth_code.
type CreatePreAuthCodeRequest struct {
	ComponentAppID string `json:"component_appid"`
}

// CreatePreAuthCodeResponse create pre_auth_code response.
type CreatePreAuthCodeResponse struct {
	PreAuthCode string `json:"pre_auth_code"`
	ExpiresIn   int64  `json:"expires_in"`
}

// CreatePreAuthCode create a pre_auth_code.
//
// Wechat API docs:
// https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/pre_auth_code.html
func (s *ComponentService) CreatePreAuthCode(ctx context.Context, token string, r *CreatePreAuthCodeRequest) (*CreatePreAuthCodeResponse, error) {
	u := fmt.Sprintf("cgi-bin/component/api_create_preauthcode?component_access_token=%v", token)
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, err
	}
	wxResp := new(CreatePreAuthCodeResponse)
	_, err = s.client.Do(ctx, req, wxResp)
	if err != nil {
		return nil, err
	}
	return wxResp, nil
}

// FuncScopeCategory 权限集
type FuncScopeCategory struct {
	ID int64 `json:"id,omitempty"`
}

// FuncInfo 权限集
type FuncInfo struct {
	FuncScopeCategory FuncScopeCategory `json:"funcscope_category,omitempty"`
}

// AuthorizationInfo 授权者信息
type AuthorizationInfo struct {
	//授权方 appid
	AuthorizerAppID string `json:"authorizer_appid,omitempty"`
	// 接口调用令牌（在授权的公众号/小程序具备 API 权限时，才有此返回值）
	AuthorizerAccessToken string `json:"authorizer_access_token,omitempty"`
	// authorizer_access_token 的有效期（在授权的公众号/小程序具备API权限时，才有此返回值），单位：秒
	ExpiresIn int64 `json:"expires_in,omitempty"`
	// 刷新令牌（在授权的公众号具备API权限时，才有此返回值），
	//刷新令牌主要用于第三方平台获取和刷新已授权用户的 authorizer_access_token。
	//一旦丢失，只能让用户重新授权，才能再次拿到新的刷新令牌。用户重新授权后，之前的刷新令牌会失效
	AuthorizerRefreshToken string `json:"authorizer_refresh_token,omitempty"`
	// 授权给开发者的权限集列表
	FuncInfo []*FuncInfo `json:"func_info,omitempty"`
}

// AuthAppResponse 授权app
type AuthAppResponse struct {
	AuthorizationInfo AuthorizationInfo `json:"authorization_info"`
}

// AuthAppRequest 授权应用请求
type AuthAppRequest struct {
	ComponentAppID    string `json:"component_appid,omitempty"`
	AuthorizationCode string `json:"authorization_code,omitempty"`
}

// AuthApp 使用授权码授权app
func (s *ComponentService) AuthApp(ctx context.Context, componentAccessToken string, r *AuthAppRequest) (*AuthAppResponse, error) {
	u := fmt.Sprintf("cgi-bin/component/api_query_auth?component_access_token=%v", componentAccessToken)
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, err
	}
	resp := new(AuthAppResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// GetAuthorizerInfoRequest 获取授权方的帐号基本信息
type GetAuthorizerInfoRequest struct {
	ComponentAppID  string `json:"component_appid,omitempty"`
	AuthorizerAppID string `json:"authorizer_appid,omitempty"`
}

// ServiceTypeInfo 类别
type ServiceTypeInfo struct {
	ID int `json:"id"`
}

// VerifyTypeInfo 类别
type VerifyTypeInfo struct {
	ID int `json:"id"`
}

// BusinessInfo 开通状态
type BusinessInfo struct {
	// 是否开通微信门店功能
	OpenStore int
	// 是否开通微信扫商品功能
	OpenScan int
	// 是否开通微信支付功能
	OpenPay int
	// 是否开通微信卡券功能
	OpenCard int
	// 是否开通微信摇一摇功能
	OpenShake int
}

// NetWork 小程序网络
type NetWork struct {
	RequestDomain   []string `json:"RequestDomain"`
	WsRequestDomain []string `json:"WsRequestDomain"`
	UploadDomain    []string `json:"UploadDomain"`
	DownloadDomain  []string `json:"DownloadDomain"`
	BizDomain       []string `json:"BizDomain"`
	UDPDomain       []string `json:"UDPDomain"`
}

// Category 小程序类目
type Category struct {
	First  string `json:"first,omitempty"`
	Second string `json:"second,omitempty"`
}

// MiniProgramInfo 小程序信息
type MiniProgramInfo struct {
	Network     NetWork
	Categories  []*Category
	VisitStatus int
}

// AuthorizerInfo 帐号信息
type AuthorizerInfo struct {
	// 昵称
	Nickname string `json:"nick_name"`
	// 头像
	HeadImg string `json:"head_img"`
	// object	公众号类型
	ServiceTypeInfo *ServiceTypeInfo `json:"service_type_info"`
	// object	公众号认证类型
	VerifyTypeInfo *VerifyTypeInfo `json:"verify_type_info"`
	// 原始 ID
	Username string `json:"user_name"`
	// 主体名称
	PrincipalName string `json:"principal_name"`
	// 公众号所设置的微信号，可能为空
	Alias string `json:"alias"`
	// object	用以了解功能的开通状况（0代表未开通，1代表已开通），详见business_info 说明
	BusinessInfo BusinessInfo `json:"business_info"`
	// 二维码图片的 URL，开发者最好自行也进行保存
	QRCodeURL       string           `json:"qrcode_url"`
	Signature       string           `json:"signature"`
	MiniProgramInfo *MiniProgramInfo `json:"MiniProgramInfo"`
}

// GetAuthorizerInfoResponse 获取授权方的帐号基本信息
type GetAuthorizerInfoResponse struct {
	AuthorizationInfo AuthorizationInfo `json:"authorization_info"`
	AuthorizerInfo    AuthorizerInfo    `json:"authorizer_info"`
}

// GetAuthorizerInfo 获取授权方的帐号基本信息
func (s *ComponentService) GetAuthorizerInfo(ctx context.Context, componentAccessToken string, r *GetAuthorizerInfoRequest) (*GetAuthorizerInfoResponse, error) {
	u := fmt.Sprintf("cgi-bin/component/api_get_authorizer_info?component_access_token=%v", componentAccessToken)
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, err
	}
	resp := new(GetAuthorizerInfoResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// GetAuthorizerTokenRequest 获取授权者token
type GetAuthorizerTokenRequest struct {
	ComponentAppID         string `json:"component_appid,omitempty"`
	AuthorizerAppID        string `json:"authorizer_appid,omitempty"`
	AuthorizerRefreshToken string `json:"authorizer_refresh_token,omitempty"`
}

// GetAuthorizerTokenResponse 获取授权方的token
type GetAuthorizerTokenResponse struct {
	AuthorizerAccessToken  string `json:"authorizer_access_token,omitempty"`
	ExpiresIn              int64  `json:"expires_in,omitempty"`
	AuthorizerRefreshToken string `json:"authorizer_refresh_token,omitempty"`
}

// GetAuthorizerToken 获取授权方的token
func (s *ComponentService) GetAuthorizerToken(ctx context.Context, componentAccessToken string, r *GetAuthorizerTokenRequest) (*GetAuthorizerTokenResponse, error) {
	u := fmt.Sprintf("cgi-bin/component/api_authorizer_token?component_access_token=%v", componentAccessToken)
	req, err := s.client.NewRequest(http.MethodPost, u, r)
	if err != nil {
		return nil, err
	}
	resp := new(GetAuthorizerTokenResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// JsCode2SessionRequest 小程序登录
type JsCode2SessionRequest struct {
	AppID          string `json:"appid,omitempty"`
	JSCode         string `json:"js_code,omitempty"`
	ComponentAppID string `json:"component_appid,omitempty"`
}

// JsCode2SessionResponse 小程序登录
type JsCode2SessionResponse struct {
	OpenID     string `json:"openid,omitempty"`
	SessionKey string `json:"session_key,omitempty"`
	UnionID    string `json:"unionid,omitempty"`
}

// JsCode2Session 小程序登录
func (s *ComponentService) JsCode2Session(ctx context.Context, componentAccessToken string, r *JsCode2SessionRequest) (*JsCode2SessionResponse, error) {
	u := fmt.Sprintf(
		"sns/component/jscode2session?component_access_token=%v&appid=%v&js_code=%v&grant_type=authorization_code&component_appid=%v",
		componentAccessToken,
		r.AppID,
		r.JSCode,
		r.ComponentAppID)
	req, err := s.client.NewRequest(http.MethodGet, u, r)
	if err != nil {
		return nil, err
	}
	resp := new(JsCode2SessionResponse)
	_, err = s.client.Do(ctx, req, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}
